# -*- coding: utf-8 -*-

# set PYTHONPATH=D:\pycharm\pywork\django-vue-admin_project\iot_project\backend
import binascii
import sys

from pandas.plotting import table

print('sys.path', sys.path)

import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
import django
django.setup()

import datetime
import threading
import paho.mqtt.client as mqtt
from threading import Thread
import logging
from iot.models import Point, Cabinet
from common.tdengine import load_tdengine_pool
from django.db import close_old_connections
import json
# publish_topic = 'iot/temp/trans'
publish_topic = 'iot/temp1'

_logger = logging.getLogger(__file__)
# host = '192.168.0.244'
host = '39.98.122.153'
TEMP_TYPE = 'T'

# 该函数的目的是将一个传感器值发布到MQTT主题，并根据该值与设定的警告阈值比较结果，发布相应的警告信息
# def trans(client, value, table):
#     # 将参数table的值赋给变量key
#     key = table
#     value_now = round(value, 2)
#     payload = {key: value_now}
#     client.publish(publish_topic, json.dumps(payload, ensure_ascii=False))
#     points = Point.objects.filter(code=table)
#     warm_warning = points.first().cabinet.warm_warning
#     warm_early_warning = points.first().cabinet.warm_early_warning
#     if warm_warning:
#         if value_now > warm_warning:
#             client.publish(publish_topic, json.dumps({key+'_warn': 1}, ensure_ascii=False))
#             return
#     if warm_early_warning:
#         if value_now > warm_early_warning:
#             client.publish(publish_topic, json.dumps({key+'_warn': 1}, ensure_ascii=False))
#             return
#     client.publish(publish_topic, json.dumps({key+'_warn': 0}, ensure_ascii=False))


class Sub(Thread):
    def __init__(self, topic, username, password, host, port, client_id):
        super().__init__()
        self.topic = topic
        self.client = mqtt.Client(client_id)
        self.client.username_pw_set(username, password)
        self.client.connect(host=host, port=port)
        self.client.on_connect = self.on_connect
        self.client.on_message = self.on_message
        self.state = True
        self.lt = None

    def on_connect(self, client, userdata, flags, rc):
        rc = str(rc)
        if rc == '0':
            self.client.subscribe(self.topic)
            print("链接成功")
        else:
            _logger.info(f'连接失败: 状态码为{rc}')

    def on_message(self, client, userdata, msg):
        try:
            payload = msg.payload
            # 使用binascii.b2a_hex函数将二进制负载转换为十六进制表示的字符串，然后使用decode方法将其解码为UTF-8字符串。
            str_data = binascii.b2a_hex(payload).decode('utf-8')
            # 从转换后的字符串中移除前6个字符
            str_data = str_data[6:]
            # 获取当前的时间
            now_time = datetime.datetime.now()
            # 循环36次0-35
            print(str_data)
            for i in range(0, 36):
                # 调用一个函数来关闭旧的数据库连接，以避免连接泄露。
                close_old_connections()
                # 计算当前数据片段的起始和结束索引
                start = i * 4
                end = (i + 1) * 4
                # 提取当前的数据片段
                each_data = str_data[start: end]
                # 检查数据片段是否等于’7fff’，这是一个特殊的值，如果等于，则将value设置为0。
                if each_data == '7fff':
                    value = 0
                else:
                    # 将十六进制数据片段转换为二进制字符串，并填充到16位。
                    by_2 = (bin(int(each_data, 16))[2:]).zfill(16)
                    # 检查二进制字符串的第一个字符是否为’0’，如果是，则数据是正数
                    if by_2[0] == '0':
                        # 将十六进制数据转换为十进制，并乘以0.1
                        value = int(each_data, 16) * 0.1
                    # 如果第一个字符不是’0’，则数据是负数
                    else:
                        # 对二进制字符串进行取反操作。
                        by_2_reserve = ''.join('1' if bit == '0' else '0' for bit in by_2)
                        # 将取反后的二进制字符串转换为十进制，加1后乘以0.1，并取负值
                        value = 0 - ((int(by_2_reserve, 2) + 1) * 0.1)
                # 将计算得到的值四舍五入到两位小数。
                value = round(value, 2)
                threading.Thread(target=Sub.write_to_td, args=(self, {'value': value, 'time': now_time,
                                                                'description': 'temp1_'+str(i+1)},)).start()
        except Exception as e:
            _logger.error(f'e: {e}')

    @staticmethod
    def write_to_td(self, data_list):
        time = data_list['time']
        value = data_list['value']
        description = data_list['description']
        # 调用Sub类的write_to_pg方法
        table, equipment = Sub.write_to_pg(time, value, description)
        # if table and equipment:
        #     trans(self.client, value, table)
        with load_tdengine_pool().get() as cursor:
            sql = f"INSERT INTO {table} USING iot TAGS ('{equipment}') VALUES ('{time}', {value});"
            cursor.execute(sql)

    @staticmethod
    def write_to_pg(time, value, description):
        point = Point.objects.filter(description=description).first()
        Cabinet.objects.filter(description=description).first()
        if not point:
            # _logger.info('请在后台配置相关点位')
            # return None, None
            point = Point.objects.create(
                code=point.code,
                description=description,
                value=value,
                update_datetime=time,
                # TODO 假数据
                cabinet_id=5,
                equipment = point.cabinet.code
            )
            _logger.info(f"新点位 {description} 已插入")
            # TODO 返回table, equipment数据
            return
        else:
            point.value = value
            point.update_datetime = time
            point_code = point.code
            equipment = point.cabinet.code
            point.save()
            return point_code, equipment

    def run(self):
        self.client.loop_forever()


if __name__ == '__main__':
    Sub(topic='iot/temp1', username='emqx', password='public', host='39.98.122.153', port=1883, client_id='iot_temp1_sub_39').start()
